<?php

// Namespace

namespace Loop;


/**
 * CTimeHelper is a helper that contains various functions to help developers deal with date/time
 *
 * @package		Loop
 * @category	Helper
 */

class CTimeHelper
{
	/**
	 * Checks whether a period is valid
	 *
	 * @param	int 	$timeOfStart	The time of start of the period
	 * @param	int		$timeOfClosure	The end of the period
	 */
	
	public function checkPeriod($timeOfStart, $timeOfClosure)
	{
		// No need to go further if one of the times is null
		
		if
		(
			(is_null($timeOfStart) === true) ||
			(is_null($timeOfClosure) === true)
		)
		{
			return;
		}
		
		
		// Is the time of start greater than the time of closure?
		
		if ($timeOfStart > $timeOfClosure) 
		{
			e
			(
				EXCEPTION_TIME_PERIOD_NOT_VALID,
				array
				(
					'timeOfClosure' => $timeOfClosure,
					'timeOfStart' => $timeOfStart
				)
			);
		}
	}
	
	
	/**
	 * Checks whether a time fits within a period
	 *
	 * @param	int		$time			The time to check
	 * @param	int		$timeOfStart	The time of start of the period
	 * @param	int		$timeOfClosure	The time of closure of the period
	 */
	
	public function checkTimeAgainstPeriod($time, $timeOfStart, $timeOfClosure)
	{
		// Make sure the time fits into the period
		
		if
		(
			(is_null($timeOfStart) === false) &&
			(is_null($timeOfClosure) === false) &&
			(
				($time < $timeOfStart) ||
				($time > $timeOfClosure)
			)
		)
		{
			e
			(
				EXCEPTION_TIME_NOT_IN_PERIOD,
				array
				(
					'time' => $time,
					'timeOfClosure' => $timeOfClosure,
					'timeOfStart' => $timeOfStart
				)
			);
		}
	}


	/**
	 * Returns the age following given time of birth and optional time of closure
	 *
	 * @param	int		$timeOfBirth		The time of birth
	 * @param	int		$timeOfClosure		The time of closure (the current time by default)
	 *
	 * @return	int		The age
	 */

	public function computeAge($timeOfBirth, $timeOfClosure = null)
	{
		if (empty($timeOfBirth) ===  true)
		{
			return;
		}


		// Ensure that the time of closure is not null

		if (is_null($timeOfClosure) === true)
		{
			$timeOfClosure = time();
		}


		// Ensure that the period is valid

		$this->checkPeriod($timeOfBirth, $timeOfClosure);

		
		$dayOfBirth = date('d', $timeOfBirth);
		$monthOfBirth = date('n', $timeOfBirth);
		$yearOfBirth = date('Y', $timeOfBirth);

		$dayOfClosure = date('d', $timeOfClosure);
		$monthOfClosure = date('n', $timeOfClosure);
		$yearOfClosure = date('Y', $timeOfClosure);


		// Calculates the difference between the year of closure and the year of birth

		$age = $yearOfClosure - $yearOfBirth;


		if
		(
			$monthOfBirth > $monthOfClosure || 
			( 
				$monthOfBirth == $monthOfClosure && 
				$dayOfBirth > $dayOfClosure
			)
		)
		{
			$age--;	
		}
		

		return floor($age);		
	}
	
	
	/**
	 * Returns a timestamp according to a date (YYYY-MM-DD HH:MM:SS) and a timezone
	 *
	 * @param	string	$date		The date
	 * @param	string	$timezone	The timezone
	 *
	 * @return	int					The corresponding timestamp
	 */
	
	public function convertDateToTimestamp($date, $timezone = null)
	{
		if (empty($timezone) === true)
		{
			$timezone = pref('[Loop]/localization/timezone');
		}


		return strtotime($this->formatDateWithTimezone($date, $timezone));
	}
	

	/**
	 * Converts a date to the format using a given timezone
	 * 
	 * @param	string		$date				The date
	 * @param	string		$timezone			The timezone
	 * @param 	string 		$format 			The date format (e.g: DATE_W3C)
	 * @param 	string 		$timezoneToConvert	The timezone to convert
	 *	
	 * @return	string					The formated date 
	 */
	
	public function convertDateToTimezone($date, $timezone = null, $format = null, $timezoneToConvert = null)
	{
		//

		if (empty($format) === true)
		{
			$format = DATE_W3C;
		}


		// By default the timezone is to the Loop preference timezone

		if (is_null($timezone) === true)
		{
			$dateTimezone =  new \DateTimezone(pref('[Loop]/localization/timezone'));			
		}
		else
		{
			$dateTimezone =  new \DateTimezone($timezone);
		}

		
		$dateTime = new \DateTime($date, $dateTimezone);


		// By default convert to the Loop preference timezone

		if (is_null($timezoneToConvert) === true)
		{
			$finalDateTimezone =  new \DateTimezone(pref('[Loop]/localization/timezone'));			
		}
		else
		{
			$finalDateTimezone =  new \DateTimezone($timezoneToConvert);
		}


		// Change the timezone

		$dateTime->setTimezone($finalDateTimezone);


		// Format the date to the format

		$finalDate = $dateTime->format($format);


		return $finalDate;		
	}	

	
	/**
	 * Converts a timestamp to a date
	 *
	 * @param	int 	$time		The time
	 * @param	string	$timezone	The timezone
	 * @param	string	$format		The format of the date
	 *
	 * @return	string				The corresponding date
	 */
	
	public function convertTimestampToDate($time, $timezone = null, $format = null)
	{
		// Store the current timezone

		$previousTimezone = pref('[Loop]/localization/timezone');


		// If a timezone was given, use it

		if (empty($timezone) === false)
		{
			pref('[Loop]/localization/timezone', $timezone);
		}


		// If no format was given, use the default one

		if (empty($format) === true)
		{
			$format = 'Y-m-d H:i:s';
		}


		// Convert the timestamp to a date

		$date = date($format, $time);


		// Use the previous timezone

		pref('[Loop]/localization/timezone', $previousTimezone);


		return $date;
	}


	/**
	 * Fixes the period to ensure that the start/closure and metric make sense
	 *
	 * @param	int		$timeOfStart	The time of start of the period
	 * @param	int		$timeOfClosure	The time of closure of the period
	 * @param	string	$metric			The metric of the period
	 *
	 * @return	int						The time of closure once fixed
	 */
	
	public function fixPeriod(&$timeOfStart, &$timeOfClosure, &$metric)
	{
		// Set default values, if needed
		
		if (is_null($timeOfStart) === true)
		{
			$timeOfStart = time();
		}
		
		if (is_null($timeOfClosure) === true)
		{
			$timeOfClosure = time();
		}
		
		if (empty($metric) === true)
		{
			$metric = pref('[Loop]/time/metric');
		}


		// Check that period is valid

		$this->checkPeriod($timeOfStart, $timeOfClosure);


		// Get the number of days/weeks/months between start and closure

		$interval = $this->getTimeInterval($timeOfStart, $timeOfClosure, $metric, false);
		

		// We cannot have an interval equal to zero

		if ($interval <= 0)
		{
			$interval = 1;
		}


		// Make sure that time of start/closure have the right value

		if ($metric == METRIC_DAY)
		{
			// Start at midnight!

			$day = date('d', $timeOfStart);
			$month = date('m', $timeOfStart);
			$year = date('Y', $timeOfStart);
			
			$timeOfStart = mktime(0, 0, 0, $month, $day, $year);

			
			// End on at 23:59
			
			$day = date('d', $timeOfClosure);
			$month = date('m', $timeOfClosure);
			$year = date('Y', $timeOfClosure);

			$timeOfClosure = mktime(23, 59, 59, $month, $day, $year);
		}
		else if ($metric == METRIC_WEEK)
		{
			// Start on a Monday

			if (date('N', $timeOfStart) != 1)
			{
				$timeOfStart = strtotime('last Monday', $timeOfStart);	
			}
			
			$day = date('d', $timeOfStart);
			$month = date('m', $timeOfStart);
			$year = date('Y', $timeOfStart);
			
			$timeOfStart = mktime(0, 0, 0, $month, $day, $year);

			
			// End on a Sunday
			
			if (date('N', $timeOfClosure) != 7)
			{
				$timeOfClosure = strtotime('next Sunday', $timeOfClosure);	
			}
			
			$day = date('d', $timeOfClosure);
			$month = date('m', $timeOfClosure);
			$year = date('Y', $timeOfClosure);

			$timeOfClosure = mktime(23, 59, 59, $month, $day, $year);
		}
		else if ($metric == METRIC_MONTH)
		{
			// Start has to be the first day of the month
			
			$day = 1;
			$month = date('m', $timeOfStart);
			$year = date('Y', $timeOfStart);
			$timeOfStart = mktime(0, 0, 0, $month, $day, $year);

			// Calcul interval between first day in the month for timeOfStart and first day in the month for timeOfClosure

			$tempTimeOfClosure = mktime(0, 0, 0, date('m', $timeOfClosure), $day, date('y', $timeOfClosure));
			$interval = $this->getTimeInterval($timeOfStart, $tempTimeOfClosure, $metric, false);

			$timeForComparison = mktime(0, 0, 0, $month, date('d'), $year);

			
			// Closure has to be the last one

			$intervalInMonths = $interval * 1;


			$month += ($intervalInMonths + 1);
	
			$day = intval(date('t', mktime(0, 0, 0, $month, 1, $year)));	
			$timeOfClosure = mktime(23, 59, 59, $month, $day, $year);


			// Remove number of day between 1 and today in the month

			$month -= $this->getTimeInterval($timeOfStart, $timeForComparison , $metric, false);

			$day = date('d');

			$timeOfClosure = mktime(23, 59, 59, ceil($month), $day, $year);

		}
		else if ($metric == METRIC_QUARTER)
		{
			// Start has to be the first day of the month

			$day = 1;
			$month = date('m', $timeOfStart);
			$year = date('Y', $timeOfStart);

			if ($month < 4)
			{
				$month = 1;
			} 
			else if ($month < 7)
			{
				$month = 4;
			}
			else if ($month < 10)
			{
				$month = 7;
			}
			else
			{
				$month = 12;
			}
			
			$timeOfStart = mktime(0, 0, 0, $month, $day, $year);
			
			
			// Closure has to be the last one
			
			$intervalInMonths = $interval * 3;
			$month += ($intervalInMonths - 1);
			$day = intval(date('t', mktime(0, 0, 0, $month, 1, $year)));

			$timeOfClosure = mktime(23, 59, 59, $month, $day, $year);
		}
		else if ($metric == METRIC_YEAR)
		{
			// Start has to be the first day of the month

			$day = 1;
			$month = 1;
			$year = date('Y', $timeOfStart);
			
			$timeOfStart = mktime(0, 0, 0, $month, $day, $year);

			
			// Closure has to be the last one
			
			$intervalInMonths = $interval * 12;
			$month += ($intervalInMonths - 1);
			$day = intval(date('t', mktime(0, 0, 0, $month, 1, $year)));

			$timeOfClosure = mktime(23, 59, 59, $month, $day, $year);
		}


		// Make sure the metric is adapted to the interval
		
		$limitOfMetric = pref('[Loop]/time/limit/' . $metric);

		if
		(
			($limitOfMetric != null) &&
			($interval > $limitOfMetric)
		)
		{
			// Define next metric

			if ($metric == METRIC_DAY)
			{
				$metric = METRIC_WEEK;
			}

			if ($metric == METRIC_WEEK)
			{
				$metric = METRIC_MONTH;
			}
			
			if ($metric == METRIC_MONTH)
			{
				$metric = METRIC_QUARTER;
			}
			
			if ($metric == METRIC_QUARTER)
			{
				$metric = METRIC_YEAR;
			}


			// Fix the period with the new metric

			$this->fixPeriod($timeOfStart, $timeOfClosure, $metric);
		}
	}
	
	
	/**
	 * Formats a date to the DATE_W3C format using a given timezone
	 * 
	 * @param	string	$date		The date
	 * @param	string	$timezone	The timezone
	 *
	 * @return	string				The date once adapted
	 */
	
	public function formatDateWithTimezone($date, $timezone)
	{
		// Create a timezone object and a date object
		
		$dateTimezone = new \DateTimezone($timezone);
		$dateTime = new \DateTime($date, $dateTimezone);
		
		
		// Format the date to the W3C format
		
		$finalDate = $dateTime->format(DATE_W3C);

		
		return $finalDate;
	}
	
		
	/**
	 * Formats a timestamp into a date according to the timezone
	 * 
	 * @param	int		$time		The timestamp 
	 * @param	string	$format		The format
	 * @param	string	$timezone	The timezone
	 *
	 * @return	string				The date
	 */
	
	public function formatDateTimezone($timestamp, $format, $timezone)
	{
		// Store the previous timezone

		$previousTimezone = pref('[Loop]/localization/timezone');


		// Temporarily set timezone to the one given

		pref('[Loop]/localization/timezone', $timezone);


		// Convert the timestamp

		$date = date($format, (int) $timestamp);


		// Revert back to the default timezone

		pref('[Loop]/localization/timezone', $previousTimezone);


		return $date;
	}
	
	
	/**
	 * Creates a data set from a given period / metric
	 *	
	 * @param 	array		$objects 		The array of objects
	 * @param 	array 		$primaryKeys 	The array of keys
	 * @param 	int 		$timeOfStart 	The period time of start
	 * @param 	int 		$timeOfClosure 	The period time of closure
	 * @param 	string 		$metric 		The metric
	 * @param 	string 		$dateFormat 	The date format
	 * @param 	array 		$value 			The array of values
	 * 
	 * @return 	array 						The array of elements for each given objects on a given period
	 */
	
	public function createArrayFromPeriod($objects, $primaryKeys, $timeOfStart, $timeOfClosure, $metric, $dateFormat, $value = null)
	{
		// Define the metric of increment

		$increment = 1;
		$metricOfIncrement = $metric;

		if ($metric == METRIC_QUARTER)
		{
			$increment = 3;
			$metricOfIncrement = METRIC_MONTH;
		}


		// Build the data set
		
		$result = array();

		foreach ($objects as $object) 
		{
			$objectId = $object->getId();	

			$result[$objectId] = array();

			foreach ($primaryKeys as $primaryKey)
			{
				//$result[$primaryKey] = array();
				
				for
				(
					$i = $timeOfStart;
					$i <= $timeOfClosure;
					$i = strtotime(date('Y-m-d' , $i) . ' +' . $increment . ' ' . $metricOfIncrement . 's')
				)
				{
					$result[$objectId][$primaryKey][date($dateFormat, $i)] = $value;
				}
			}
		}

		
		return $result;
	}


	/**
	* This function return the time in minutes, hours, days, month or years beetween the time of publication and current time.
	*
	* @param	int		$timeOfStart	The time of start of the period
	* @param	int		$timeOfClosure	The time of closure of the period
	*
	* @return	string					The appropriate metric
	*/

	public function defineAppropriateMetric($timeOfStart, $timeOfClosure)
	{
		$diff = $timeOfClosure - $timeOfStart;

		// If difference is less than one minute

		if ($diff < 60)
		{
			return METRIC_MINUTE;
		}

		// If difference is less than one hour

		elseif (($diff /= 60) < 60)
		{
			return METRIC_MINUTE;
		}

		// If difference is less than one day

		elseif (($diff /= 60) < 24)
		{
			return METRIC_HOUR;
		}

		// If difference is less than one month

		elseif (($diff /= 24) < 30)
		{
			return METRIC_DAY;
		}

		// If difference is less than one year

		elseif (($diff /= 30) < 12)
		{
			return METRIC_MONTH;
		}

		// Else display the number of past year

		else
		{
			return METRIC_YEAR;
		}
	}


	
	
	/**
	 * Calculates the interval between 2 timestamps
	 *
	 * @param	int		$timeOfStart	The time at which the period starts
	 * @param	int		$timeOfClosure	The period at which the period ends
	 * @param	string	$metric			The metric in which the interval should be converted
	 * @param	bool	$roundInterval	True to round the interval (e.g. 2 weeks instead of 1.9), false otherwise
	 *
	 * @return	float					The interval
	 */
	
	public function getTimeInterval($timeOfStart, $timeOfClosure, $metric = null, $roundInterval = false)
	{
		if (is_null($metric) === true)
		{
			$metric = $this->defineAppropriateMetric($timeOfStart, $timeOfClosure);
		}

		// Is the metric supported?

		$constantName = 'METRIC_SECONDS_PER_' . strtoupper($metric);

		if (defined($constantName) === false)
		{
			e
			(
				EXCEPTION_TIME_METRIC_NOT_SUPPORTED,
				array
				(
					'metric' => $metric
				)
			);
		}


		// How many seconds between the 2 timestamps?
		
		$interval = $timeOfClosure - $timeOfStart;


		// Convert the interval to the given metric

		$nbSecondsPerMetric = constant($constantName);
		$interval = intval($interval) / $nbSecondsPerMetric;


		// Round the interval, if needed
		
		if
		(
			($roundInterval === true) &&
			(intval($interval) != $interval)
		)
		{
			return ceil($interval);
		}


		return $interval;
	}
	
	
	/**
	 * Returns the period options (periodTimeOfStart, periodTimeOfClosure, periodMetric) according to a period code
	 *
	 * @param	string	$periodCode				The code of the period
	 * @param 	int 	$periodTimeOfStart		The time of start of the period
	 * @param 	int 	$periodTimeOfClosure 	The time of closure of the period
	 * @param   string 	$periodMetric 			The metric of the period
	 *
	 * @return	array							The period options
	 */
	
	public function convertPeriodCode($periodCode, &$periodTimeOfStart, &$periodTimeOfClosure, &$periodMetric)
	{
		// Ensure that given periode code is valid
		
		$allowedPeriodCodes = array
		(
			PERIOD_CURRENT_DAY,
			PERIOD_CURRENT_MONTH,
			PERIOD_CURRENT_WEEK,
			PERIOD_CURRENT_YEAR,
			PERIOD_LAST_7_DAYS,
			PERIOD_LAST_30_DAYS,
			PERIOD_LAST_12_MONTHS,
			PERIOD_LAST_YEAR,
			PERIOD_YEAR_OVER_YEAR
		);
		
		
		if (in_array($periodCode, $allowedPeriodCodes) === false)
		{
			e
			(
				EXCEPTION_PERIOD_CODE_NOT_VALID,
				array
				(
					'periodCode' => $periodCode
				)
			);
		}


		// Convert the period code into a metric, times of start / closure
				
		if ($periodCode == PERIOD_CURRENT_DAY)
		{
			$periodMetric = METRIC_DAY;
			$periodTimeOfStart = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
			$periodTimeOfClosure = time();
		}
		else if ($periodCode == PERIOD_CURRENT_MONTH)
		{
			$currentMonthNbDays = intval(date("t", mktime(0, 0, 0, date('m'), 1, date('Y'))));

			$periodMetric = METRIC_DAY;
			$periodTimeOfStart = mktime(0, 0, 0, date('m'), 1, date('Y'));
			$periodTimeOfClosure = mktime(23, 59, 59, date('m'), $currentMonthNbDays, date('Y'));
		}
		else if ($periodCode == PERIOD_CURRENT_WEEK)
		{
			// If today is monday we are at the beginning of the current week
			
			if (date('Y-m-d', strtotime('Monday')) == date('Y-m-d', time()))
			{
				$currentMondayTimestamp = strtotime('Monday');
			}
			
			// Else we take the last monday
			
			else
			{
				$currentMondayTimestamp = strtotime('last Monday');
			}
			
			$currentSundayTimestamp = strtotime('Sunday');
			
			
			//

			$currentMondayDay =  date('d', $currentMondayTimestamp);
			$currentMondayMonth =  date('m', $currentMondayTimestamp);
			$currentMondayYear =  date('Y', $currentMondayTimestamp);
			
			$currentSundayDay =  date('d', $currentSundayTimestamp);
			$currentSundayMonth =  date('m', $currentSundayTimestamp);
			$currentSundayYear =  date('Y', $currentSundayTimestamp);
			
			
			//

			$periodMetric = METRIC_DAY;
			$periodTimeOfStart = mktime(0, 0, 0, $currentMondayMonth, $currentMondayDay, $currentMondayYear);
			$periodTimeOfClosure = mktime(23, 59, 59, $currentSundayMonth, $currentSundayDay, $currentSundayYear);
		}
		else if ($periodCode == PERIOD_CURRENT_YEAR)
		{
			//

			$periodMetric = METRIC_MONTH;
			$periodTimeOfStart = mktime(0, 0, 0, 1, 1, date('Y'));
			$periodTimeOfClosure = mktime(23, 59, 59, 12, 31, date('Y'));
		}
		else if ($periodCode == PERIOD_LAST_12_MONTHS)
		{
			//
			
			$periodMetric = METRIC_MONTH;
			$periodTimeOfStart = mktime(0, 0, 0, date('m')-12, date('d'), date('Y'));
			$periodTimeOfClosure = time();
		}
		else if ($periodCode == PERIOD_LAST_7_DAYS)
		{
			//
			
			$periodMetric = METRIC_DAY;
			$periodTimeOfStart = mktime(0, 0, 0, date('m'), date('d')-6, date('Y'));
			$periodTimeOfClosure = time();
		}
		else if ($periodCode == PERIOD_LAST_30_DAYS)
		{
			//
			
			$periodMetric = METRIC_DAY;
			$periodTimeOfStart = mktime(0, 0, 0, date('m'), date('d')-29, date('Y'));
			$periodTimeOfClosure = time();
		}
		else if ($periodCode == PERIOD_LAST_YEAR)
		{
			//
			
			$periodMetric = METRIC_MONTH;
			$periodTimeOfStart = mktime(0, 0, 0, 1, 1, date('Y')-1);
			$periodTimeOfClosure = mktime(23, 59, 59, 12, 31, date('Y')-1);
		}
		else if ($periodCode == PERIOD_YEAR_OVER_YEAR)
		{
			//
			
			$periodMetric = METRIC_YEAR;
			$periodTimeOfStart = mktime(0, 0, 0, 1, 1, date('Y') - 2);
			$periodTimeOfClosure = mktime(23, 59, 59, 12, 31, date('Y'));
		}
	}
	
	
	/**
	 * Gives the previous time of start and time of closure of given period, metric and interval
	 * 
	 * @param	int		$timeOfStart	The time of start
	 * @param	int		$timeOfClosure	The time of closure
	 * @param	string	$metric			The metric of the period
	 * @param	int		$decrement		The value of decrement
	 *
	 * @return	array					The previous period
	 */
	
	public function getPreviousPeriodOptions($timeOfStart, $timeOfClosure, $metric, $decrement = 1)
	{
		// No need to go further if one of the dates is null or if the metric is null
		
		if
		(
			(is_null($timeOfStart) == true) ||
			(is_null($timeOfClosure) == true) ||
			(is_null($metric) == true)
		)
		{
			return;
		}
		
		
		$previousPeriodOptions = array();
		
		
		// Compute the previous period

		$nbDaysInterval = $this->getTimeInterval($timeOfStart, $timeOfClosure, $metric, true);


		$dateOfStart = $this->convertTimestampToDate($timeOfStart);
		$dateOfClosure = $this->convertTimestampToDate($timeOfClosure);
		
		
		// If the metric is month, we don't need to add the decrement into the previous date of start computation
		
		if ($metric == METRIC_MONTH)
		{
			$previousTimeOfStart = strtotime($dateOfStart .' - '. ($decrement * $nbDaysInterval) .' day');
			$previousTimeOfClosure = strtotime($dateOfClosure .' - '. (($decrement * $nbDaysInterval) + $decrement) .' day');
		}
		else
		{
			$previousTimeOfStart = strtotime($dateOfStart .' - '. (($decrement * $nbDaysInterval) + $decrement) .' day');
			$previousTimeOfClosure = strtotime($dateOfClosure .' - '. (($decrement * $nbDaysInterval)  + $decrement) .' day');
		}
		
		
		// Store the period time of start and time of closure into an array
		
		$previousPeriodOptions['timeOfStart']  = $previousTimeOfStart;
		$previousPeriodOptions['timeOfClosure']  = $previousTimeOfClosure;
		
		
		return $previousPeriodOptions;
	}
	
		
	/**
	 * Gives the previous year time of start and time of closure of given period
	 * 
	 * @param	int		$timeOfStart	The time of start
	 * @param	int		$timeOfClosure	The time of closure
	 *
	 * @return	array					The previous period
	 */
	
	public function getPreviousYearPeriodOptions($timeOfStart, $timeOfClosure)
	{
		// No need to go further if one of the dates is null or if the metric is null
		
		if
		(
			(is_null($timeOfStart) == true) ||
			(is_null($timeOfClosure) == true)
		)
		{
			return;
		}
		
		
		$previousYearPeriodOptions = array();
		
		$dateOfStartDay =  date('d', $timeOfStart);
		$dateOfStartMonth =  date('m', $timeOfStart);
		$dateOfStartYear =  date('Y',  $timeOfStart);

		$dateOfClosureDay =  date('d',  $timeOfClosure);
		$dateOfClosureMonth =  date('m',  $timeOfClosure);
		$dateOfClosureYear =  date('Y',  $timeOfClosure);
		
		
		// Get the previous year period options
		
		$previousYearTimeOfStart =  mktime(0, 0, 0, $dateOfStartMonth, $dateOfStartDay, $dateOfStartYear - 1);
		$previousYearTimeOfClosure = mktime(23, 59, 59, $dateOfClosureMonth, $dateOfClosureDay, $dateOfClosureYear - 1);
		
		
		$previousYearPeriodOptions['timeOfStart'] = $previousYearTimeOfStart;
		$previousYearPeriodOptions['timeOfClosure'] = $previousYearTimeOfClosure;
		
		
		return $previousYearPeriodOptions;
	}
	
	
	/**
	 * Gets and returns the start time from given time metric and timestamp (optional)
	 *
	 * @param	string	$metric		The time metric
	 * @param	int		$time		A timestamp
	 *
	 * @return	int					The start time
	 */

	public function getStartTimeFromMetric($metric, $time = null)
	{
		// By default we use the current time	

		$year = date('Y');
		$month = date('m');
		$day = date('d');
		$weekDayNumber = date('N');
		$hour = date('G');
		$minute = date('i');


		// Do we have a specified timestamp ?	

		if (is_null($time) === false)
		{
			$year = date('Y', $time);
			$month = date('m', $time);
			$day = date('d',  $time);
			$weekDayNumber = date('N', $time);
			$hour = date('G', $time);
			$minute = date('i', $time);     		
		}


		// Get the start time following the give metric

		if ($metric == METRIC_YEAR)
		{
			$startTime = mktime(0, 0, 0, 1, 1, $year);
		}
		else if ($metric == METRIC_QUARTER)
		{
			// We get the first month of the associated quarter, be careful, values order is very important for the calculation (floor(($month-1)/3) + 1 allows to get the month associated quarter)

			$firstMonthOfAssociatedQuarter = 3 * floor(($month-1)/3) + 1;

			$startTime = mktime(0, 0, 0, $firstMonthOfAssociatedQuarter, 1, $year);
		}
		else if ($metric == METRIC_MONTH)
		{
			$startTime = mktime(0, 0, 0, $month, 1, $year);
		}
		else if ($metric == METRIC_WEEK)
		{
			$startTime = mktime(0, 0, 0, $month, ($day - $weekDayNumber) + 1, $year);
		}
		else if ($metric == METRIC_DAY)
		{
			$startTime = mktime(0, 0, 0, $month, $day, $year);
		}
		else if ($metric == METRIC_HOUR)
		{
			$startTime = mktime($hour, 0, 0, $month, $day, $year);
		}
		else if ($metric == METRIC_MINUTE)
		{
			$startTime = mktime($hour, $minute, 0, $month, $day, $year);
		}


		return $startTime;
	} 
	
	/**
	 * Gives the pattern of a date according to the language
	 * 
	 * @param	string 	$language 		The language
	 * @param	string 	$type 			The type of the date (day, day_hour, day_hour_sec, hour, hour_sec)
	 * @param	string 	$year 			The format of the year (Y, y)
	 * @param	string 	$date_separator The separator of the date (/, ...)
	 * @param	string 	$hour_separator The separator of the hour (:, ...)
	 *
	 * @return	string 					The pattern of a date according to a given language
	 */
	
	public function getTypeFormatDate($language, $type, $year, $date_separator, $hour_separator)
	{
		if ($type == METRIC_DAY)
		{
			if ($language=='fr') return 'd'.$date_separator.'m'.$date_separator.''.$year;
			elseif ($language=='en') return 'Y'.$date_separator.'m'.$date_separator.''.'d';
			else return 'm'.$date_separator.'d'.$date_separator.''.$year;
		}
		elseif ($type=='day_hour')
		{
			if ($language=='fr') return 'd'.$date_separator.'m'.$date_separator.''.$year.' H'.$hour_separator.'i';
			elseif ($language=='en') return 'Y'.$date_separator.'m'.$date_separator.''.'d'.'  H'.$hour_separator.'i';
			else return 'm'.$date_separator.'d'.$date_separator.''.$year.' H'.$hour_separator.'i';		
		}
		elseif ($type=='day_hour_sec')
		{
			if ($language=='fr') return 'd'.$date_separator.'m'.$date_separator.''.$year.' H'.$hour_separator.'i'.$hour_separator.'s';
			elseif ($language=='en') return 'Y'.$date_separator.'m'.$date_separator.''.'d'.' H'.$hour_separator.'i'.$hour_separator.'s';
			else return 'm'.$date_separator.'d'.$date_separator.''.$year.' H'.$hour_separator.'i'.$hour_separator.'s';		
		}
		elseif ($type=='hour')
		{
			return 'H'.$hour_separator.'i';
		}
		elseif ($type=='hour_sec')
		{
			return 'H'.$hour_separator.'i'.$hour_separator.'s';
		}
		else return $year.$date_separator.''.'m'.$date_separator.'d';
	}


	/**
	 * Checks whether a time belongs to a period
	 *
	 * @param	int		$timeOfStart	The time of start of the period
	 * @param	int		$timeOfClosure	The time of closure of the period
	 * @param	int		$time			The time to check against the period
	 *
	 * @return	bool					True if $time belongs to the period, false otherwise
	 */

	public function isInPeriod($timeOfStart, $timeOfClosure, $time = null)
	{
		// Do we have a time? Otherwise use now

		if (is_null($time) === true)
		{
			$time = time();
		}


		// Is time in the interval?

		return
		(
			($time >= $timeOfStart) &&
			($time <= $timeOfClosure)
		);
	}
}

?>
